iT邦幫忙

2024 iThome 鐵人賽

DAY 21
0
Modern Web

前進React 生態系 : 技術應用與概念解析系列 第 21

Day 21 - 掌握 React 19 use API,處理 Context 和非同步資料

  • 分享至 

  • xImage
  •  

use

React 19 推出了新的 API use ,可以用來取得非同步的內容或 Promise ,也可用來取得 Context。

use 只能在 render 期間使用,只能用在 Component 或 Hook 。需要注意的是 use 並不是 Hook,是可以在條件語句或迴圈使用的。

use 取得 Context

useContext 不同的是,use 可以在條件語句或迴圈使用。

function App({ show }) {
  if (show) {
    const theme = use(ThemeContext);
    return <SomeComponent theme={theme} />;
  }

  return null;
}

use 取得 Promise

當使用 use 取得 Promise 時,通常會搭配 Suspense 和 ErrorBoundary。

  • 當 Promise 處於 pending 狀態時,會顯示 Suspense 的 fallback UI。
  • 當 Promise 成功解析後,會顯示回傳的資料。
  • 當 Promise 被拒絕(rejected)時,會觸發 ErrorBoundary 顯示 fallback UI。

範例:

import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

export default function App() {
  const userPromise = db.connect.getUsers(id);

  return (
    <div>
      <ErrorBoundary fallback={<ErrorFallback />}>
        <Suspense fallback={<Loading />}>
          <UserList userPromise={userPromise} />
        </Suspense>
      </ErrorBoundary>
    </div>
  );
}
"use client";

function UserList({ userPromise }) {
  const users = use(userPromise);

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

透過以上寫法就不用使用 useStateuseEffect來處理資料狀態。

使用 use 傳遞 Promise 注意事項

通常會建議在 Server Components 中創建 Promise,並將 Promise 當作 props 傳遞給 Client Components ,並在 Client Component 中使用 use

Server Components 中使用 async/await

如果要在 Server Component 取得資料,使用 asyncawait 就好,不需要使用 use,以下是兩者的差別:

  • 使用 asyncawait 會在執行 await 時暫停渲染,直到 await 完成後會再繼續執行。
  • 使用 use 會在取得資料後重新渲染元件。

不應該在 render 中創建 Promise

另外要注意的是不能在 render 的過程中創建的 Promise,應該使用已經創建好的 Promise。若在 render 中創建 Promise,會產生以下警告:

A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework.

範例說明:

const fetchUserData = () => {
  return fetch("https://example.com/users").then((res) => res.json());
};
const promiseFetchUserData = fetchUserData(); // 在外部創建 Promise

function UserList() {
  const data = use(fetchUserData()); //這樣會出現錯誤
  const data = use(promiseFetchUserData); // 正確用法

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

錯誤處理: ErrorBoundary 和 try-catch

在使用 use 時也需要錯誤處理。use 無法直接在 try-catch 中使用,通常要配合 ErrorBoundary。除此之外,也可以在 Promise 的 catch 中提供替代值。

使用 Promise.catch 提供替代值

const userPromise = new Promise((resolve, reject) => {
  reject();
}).catch(() => {
  return "no user"; // 提供的替代值
});

ErrorBoundary

在沒有處理錯誤時,React 會讓畫面直接崩潰。目前在 Function Component 沒有辦法建立 ErrorBoundary,需要使用 react-error-boundary 套件來處理錯誤,當錯誤發生時會顯示 fallback 的 UI 內容。

參考資料:
https://react.dev/blog/2024/04/25/react-19
https://react.dev/reference/react/use#usage
https://www.youtube.com/watch?v=AJOGzVygGcY
https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary


上一篇
Day 20 - 使用 React 19 的 useOptimistic 和 Transitions 打造順暢體驗
下一篇
Day 22 - 掌握 React 19 Metadata 與資源載入優化
系列文
前進React 生態系 : 技術應用與概念解析22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言